
#include "uniquename.h"
#include "namespace.h"

#include <cstring>

UniqueName::UniqueName()
:   m_nameSpace(NULL)
,   m_registered(false)
{
}

UniqueName::UniqueName(const std::string &name)
:   m_nameSpace(NULL)
,   m_registered(false)
{
    setName(name);
}

UniqueName::~UniqueName()
{
    if(m_nameSpace && m_registered)
        m_nameSpace->unregisterName(m_name);
}


void UniqueName::setNameSpace(NameSpace *nameSpace)
{
    if(m_nameSpace)
    {
        if(!m_name.empty() && m_registered)
        {
            m_nameSpace->unregisterName(m_name);
            m_registered = false;
        }
    }
    m_nameSpace = nameSpace;

    if(!m_name.empty())
        setName(m_name, false);
}


const std::string UniqueName::setName(const std::string &name)
{
    return setName(name, true);
};


const std::string UniqueName::setName(
    const std::string &name
,   const bool &ignoreSameName)
{
    if(!m_nameSpace)
    {
        if(name.empty())
        {
            NameSpace tempNS;
            m_name = tempNS.generateName();
        }
        else
            m_name = name;

        return m_name;
    }
    if((ignoreSameName && m_name.compare(name) == 0)
    || (name.empty() && !m_name.empty()))
        return m_name;

    bool renamed = false;

    const std::string oldName = m_name;
    std::string newName(name);

    renamed = newName.empty();
    if(renamed)
    {
        newName = m_nameSpace->generateName(newName);
        m_registered = m_nameSpace->registerName(newName);
    }
    else
        renamed = makeValid(newName, oldName, ignoreSameName);

    m_name = newName;

    return m_name;
}

bool UniqueName::operator<(const UniqueName &rhs) const
{
    if(!m_nameSpace || !rhs.m_nameSpace || m_nameSpace == rhs.m_nameSpace)
    {
        return m_name < rhs.name();
    }
    else
    {
        return m_nameSpace < rhs.m_nameSpace;
    }
}

UniqueName &UniqueName::operator=(const UniqueName &rhs)
{
    setNameSpace(rhs.nameSpace());
    setName(rhs.name());

    m_registered = rhs.m_registered;
    return *this;
}

UniqueName &UniqueName::operator=(const std::string &rhs)
{
    setName(rhs);
    return *this;
}

UniqueName &UniqueName::operator=(const char *rhs)
{
    setName(std::string(rhs));
    return *this;
}

bool UniqueName::operator==(const UniqueName &rhs) const
{
    if(m_nameSpace && rhs.nameSpace())
        return (m_nameSpace == rhs.nameSpace() && m_name == rhs.name());
    else
        return (m_name == rhs.name());
}

const bool UniqueName::makeValid(
    std::string &newName
,   const std::string &oldName
,   const bool &ignoreSameName)
{
    bool renamed = false;
    bool wasRegistered = m_registered;

    std::string temp(newName);

    // replace all whitespaces and non latin letters or numbers
    /*unsigned int i = 0;
    // remove noncharacters at the beginning
    bool firstCharPassed = false;

    while(i < temp.length())
    {
        char& c = temp[i];

        if(!firstCharPassed && ((c > 64 && c < 91) || (c > 96 && c < 123) || c == 95))
             firstCharPassed = true;

        if(!((firstCharPassed && (c > 47 && c < 58)) || (c > 64 && c < 91) || (c > 96 && c < 123) || c == 95))
        {
            temp.erase(i, 1);
            renamed = true;
        }
        else
            ++i;
    }
    // if the name was that bad, restore old name
    if(temp.length() == 0)
        temp = m_nameSpace->generateName(temp);
    */

    if(ignoreSameName && temp.compare(oldName) == 0)
    {
        newName = temp;
        return true;
    }

    // try to register new name
    m_registered = m_nameSpace->registerName(temp);
    if(!m_registered)
    {
        temp = m_nameSpace->generateName(temp, wasRegistered ? oldName : "");
        if(temp.compare(oldName) != 0)
        {
            m_registered = m_nameSpace->registerName(temp);
            renamed = true;
        }
        else
            m_registered = true;
    }
    newName = temp;

    if(newName.compare(oldName) != 0 && wasRegistered)
        m_nameSpace->unregisterName(oldName);

    return renamed;
}

inline NameSpace *UniqueName::nameSpace() const
{
    return m_nameSpace;
}

const std::string UniqueName::name() const
{
    return m_name;
}

const char *UniqueName::c_str() const
{
    return m_name.c_str();
}

bool UniqueName::operator!=(const UniqueName &rhs) const
{
    return (!(*this == rhs));
}

bool UniqueName::operator==(const std::string &rhs) const
{
    return (m_name == rhs);
}

bool UniqueName::operator!=(const std::string &rhs) const
{
    return (m_name != rhs);
}

bool UniqueName::operator==(const char *rhs) const
{
    return (0 == strcmp(m_name.c_str(), rhs));
}

bool UniqueName::operator!=(const char *rhs) const
{
    return (0 != strcmp(m_name.c_str(), rhs));
}
